--- title: Hotmax spectra keywords: fastai sidebar: home_sidebar summary: "Cherry picking the best spectra" description: "Cherry picking the best spectra" nb_path: "notebooks/40_hotmax.ipynb" ---
{% raw %}
{% endraw %}

A MA-XRF spectral image data cube contains typically a million spectra or so. Far too many to analyze them individually! Furthermore, most of these spectra have low signals and are rather noisy. A common approach to overcome computational problems is to base a further data analysis solely on the max spectrum. Such an approach is used e.g. by DataMuncher developed by Mathias Alfeld. As discussed above, the max spectrum essentially is an envelope that provides a highly informative summary of all spectra. It is important to understand that different peaks in the max spectrum envelope can originate from different pixel positions in the spectral image. This complicates attribution of the peaks directly from the max spectrum.

Locating the hotmax pixels and spectra

A more sophisticated approach is to locate for each peak in the max spectrum envelope which specific pixel spectrum is responsible for that specific peak. Loosely speaking, which pixels in the spectral image data cube are 'hotmax'? Another way to explain this is to find the specific 'hotmax' spectra that touches the corresponding max spectrum peaks.

A requisite step in the data analysis now is to find the hotmax pixels and spectra. Locating them takes a few minutes, and should be done once using the get_hotmax_spectra() function. The user is prompted to inspect and save the result in the datastack file.

{% raw %}
from maxrf4u import compute_hotmax_spectra 

compute_hotmax_spectra('RP-T-1898-A-3689.datastack')
Step 1/3: Reading hot max channel maps...
[########################################] | 100% Completed | 51.5s
Step 2/3: Locating hot max pixels...
Step 3/3: Ready with reading hot max spectra. 
Write hotmax spectra and pixels to datastack file [y/n]? y

Saved hotmax data to: RP-T-1898-A-3689.datastack
{% endraw %}

In further analysis our stored hotmax pixel indexes and hotmax spectra can now be accessed from file using the DataStack.read(<datapath>)) methods. Let's inspect the shapes of these arrays first.

{% raw %}
from maxrf4u import DataStack 
ds = DataStack('RP-T-1898-A-3689.datastack')

hotmax_spectra = ds.read('hotmax_spectra')
hotmax_pixels = ds.read('hotmax_pixels')

n_pixels, n_dims = hotmax_pixels.shape
n_spectra, n_channels = hotmax_spectra.shape 

print(f'The array of hotmax pixels contains {n_pixels} pixels. ')
print(f'Each pixel consists of {n_dims} indexes.\n')
print(f'There are {n_spectra} hotmax spectra.')
print(f'Each spectrum contains {n_channels} intensity values.')
The array of hotmax pixels contains 24 pixels. 
Each pixel consists of 3 indexes.

There are 24 hotmax spectra.
Each spectrum contains 4096 intensity values.
{% endraw %}

To get an idea, let's plot the spatial (x, y) locations of the hotmax pixels on the image of the drawing.

{% raw %}
{% endraw %}

Now let's pick one of the 24 hotmax spectra and take a closer look. Each hotmax spectrum has one peak (square red marker) that corresponds to a specific peak in the the max spectrum envelope.

{% raw %}
{% endraw %}

The measured spectrum consists of a a slowly varying baseline, the so-called the Compton ridge, with peaks added on top. Some of these peaks are caused by x-ray fluorescence of specific chemical elements. Other peaks are just noise.

The difficulty with these kind of spectra is that the noise level varies with the signal according to Poisson statistics. The variance of noise is linearly proportional to the signal level. For this reason, we observe more noise on top of the Compton ridge.

In order to distinguish significant peaks from noise it is possible to estimate a baseline with a noise envelope for the hotmax spectra with the compute_hotmax_noise()function. The algorithm used in estimating the baseline function is the rolling ball filter. In accordance with Poisson statistics, the noise level is estimated as a square root function of the baseline level.

{% raw %}
from maxrf4u import compute_hotmax_noise

compute_hotmax_noise('RP-T-1898-A-3689.datastack')
Ready computing 24 noise envelopes.                           

Write hotmax baselines and noiselines to datastack file [y/n]? y

Saved hotmax noise data to: RP-T-1898-A-3689.datastack
{% endraw %}

We can create a HotmaxAtlas object to plot all spectra with the HotmaxAtlas.plot_spectra()) method.

{% raw %}
from maxrf4u import HotmaxAtlas 
{% endraw %} {% raw %}
hma = HotmaxAtlas('RP-T-1898-A-3689.datastack')

hma.plot_spectra()
2022-08-08T16:20:25.208987 image/svg+xml Matplotlib v3.4.3, https://matplotlib.org/
{% endraw %}

Or we can plot a single spectrum with HotmaxAtlas.plot_spectrum(<nr>)) to inspect a specific hotmax spectrum.

{% raw %}
hma.plot_spectrum(4);
{% endraw %}

Each specific chemical element present is known to cause a specific peak pattern. Now we need to solve the inverse problem, which I call 'the peak pattern puzzle'. Given a spectrum, which combination of elements is likely to have caused the combination of peaks we find in the spectrum? This is the topic of the next section...

Module maxrf4u.hotmax.py

{% raw %}

class HotmaxAtlas[source]

HotmaxAtlas(datastack_file, prominence=0.2)

{% endraw %} {% raw %}

compute_hotmax_spectra[source]

compute_hotmax_spectra(datastack_file, prominence=0.35)

Collect hotmax pixels and corresponding spectra from *datastack_file*.

Ask user confirmation for saving result to datastack file.
{% endraw %} {% raw %}

compute_hotmax_noise[source]

compute_hotmax_noise(datastack_file, radius=200, alpha=0.6, beta=0.1)

Utility function to get baselines and noiselines from hotmax spectra in *datastack_file*.

Use once to compute base noise envelopes. Ask user confirmation for saving result to datastack file.
{% endraw %} {% raw %}
{% endraw %}